﻿package duplexpipe;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import duplexpipe.doc.EnHelp;
import duplexpipe.doc.Help;
import duplexpipe.sni.CommonUtil;
import duplexpipe.sni.CommunicatorFactory;
import duplexpipe.sni.CreateConnecterPipe;
import duplexpipe.sni.CreateListenPipe;
import duplexpipe.sni.NetCommunicator;
import duplexpipe.sni.PipeIO;
import duplexpipe.sni.TCPListener;
import duplexpipe.utils.Getopt;
import duplexpipe.utils.NetInfo;
import duplexpipe.utils.Verboser;

/**
 * <p>
 * <B>DuplexPipe: </B>双向管道！
 * </p>
 * <p>
 * 本程序是一个双向管道。传统的管道只能从一端输入、一端输出。双向管道不仅可以<br>
 * 让进程 A 的输出作为进程 B 的输入，也会让进程 B 的输出作为进程 A 的输入。<br>
 * 这样就可以让两个进程实现交流。
 * </p>
 * <p>
 * 本程序主要是 TCP 转发工具。允许监听本地端口，也可以主动连接远程端口。<br>
 * 如果和瑞士军刀“nc -e”配合使用， 就能实现本地进程和网络进程任意沟通。
 * </p>
 * <p>
 * 程序的具体使用方法可以参见 help()。
 * </p>
 * 
 * @author redraiment
 * @version 0.3.0
 * @category Main
 */
public class DuplexPipe {
	public final static String version = "0.1.1";
	public final static String author = "endsock";
	public final static String email = "endsock@gmail.com";
	public final static String homepage = "http://www.google.com";
	public final static int connecterNum = 15;
	private final static boolean isSingle = true;
	public final static int bufferSize = 1024;
	public final static byte[] ping = "ping".getBytes();
	public final static byte[] pong = "pong".getBytes();

	private static Help help = new EnHelp();

	public static ConcurrentMap<String, Socket> clientMap = new ConcurrentHashMap<String, Socket>();

	public static BlockingQueue<Socket> connecterQueue = new ArrayBlockingQueue<Socket>(
			connecterNum);


	public static void main(String[] args) {
		Verboser v = Verboser.getVerboser();
		NetCommunicator[] nc = new NetCommunicator[2];
		PipeIO[] p = new PipeIO[2];
		NetInfo[] ni = null;
		Thread duplexPipeThread = null;

		try {
			ni = Getopt.parse(args);
		} catch (Exception e) {
			help.manual();
		}

		// Listener模式
		if (ni[0].getType() == 1 && ni[1].getType() == 1) {
			try {
				// 监听客户
				TCPListener listenerForClient = new TCPListener(ni[1].getPort());
				listenerForClient.setMap(clientMap);
				Thread thread = new Thread(listenerForClient);
				thread.start();
				
				// 监听连接端的轮询
				TCPListener listenerForConnecter = new TCPListener(
						ni[0].getPort());
				listenerForConnecter.setConnecterQueue(connecterQueue);
				Thread thread2 = new Thread(listenerForConnecter);
				thread2.start();

				while (true) {
					for (String item : clientMap.keySet()) {
						nc[1] = CommunicatorFactory.createNetCommunicator(
								clientMap.get(item), ni[1], "T"); // 用户
						CreateListenPipe createListenPipe = new CreateListenPipe();
						createListenPipe.setClientSocket(nc[1]);
						createListenPipe.setBridgeInfo(ni[0]);
						createListenPipe.start();

						clientMap.remove(item);
					}
					Thread.sleep(10);
				}

			} catch (IOException e1) {
				e1.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// Connecter模式
		if (ni[0].getType() == 0 && ni[1].getType() == 0) {
			try {

				while (true) {
					try {
						nc[0] = CommunicatorFactory.createNetCommunicator(null,
								ni[0], "C"); // ConnectBridge
					} catch (IOException e) {
						CommonUtil.LogPrint("ConnectBridge建立连接超时");
						try {
							if (nc[0] != null) {
								nc[0].close();
							}
							
						} catch (IOException e1) {
							CommonUtil.LogPrint(e1.getMessage());
						}
						continue;
					}
					
					CreateConnecterPipe clientpipe = new CreateConnecterPipe();
					clientpipe.setBridgeSocket(nc[0]);
					clientpipe.setClientInfo(ni[1]);

					clientpipe.start();

					Thread.sleep(500);
				}
			} catch (InterruptedException e) {
				// TODO: handle exception
			}
		}

	}

}
